package com.stream;

import lombok.Builder;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @Author:zxh
 * @Description: Optional test
 * @Date: 2020/11/3
 * @Modified By:
 */
public class OptionalTest {

    /**
     * 可能包含或不包含非空值的容器对象。 如果一个值存在， isPresent()将返回true和get()将返回值。
     * 提供依赖于存在或不存在包含值的其他方法，例如orElse() （如果值不存在则返回默认值）和ifPresent() （如果值存在则执行代码块）。
     * 这是一个value-based课; 使用身份敏感的操作（包括引用相等（的==上的实例），标识哈希码，或同步） Optional可具有不可预测的结果，应当避免
     */
    /**
     * 为了解决空指针异常，在Java8之前需要使用if-else这样的语句去防止空指针异常，而在Java8就可以使用Optional来解决。
     * Optional可以理解成一个数据容器，甚至可以封装null，并且如果值存在调用isPresent()方法会返回true
     */
    /**
     * 1.boolean equals(Object obj)：判断其他对象是否等于 Optional；
     * 2. Optional<T> filter(Predicate<? super <T> predicate)：如果值存在，并且这个值匹配给定的 predicate，返回一个Optional用以描述这个值，否则返回一个空的Optional；
     * 3. <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)：如果值存在，返回基于Optional包含的映射方法的值，否则返回一个空的Optional；
     * 4. T get()：如果在这个Optional中包含这个值，返回值，否则抛出异常：NoSuchElementException；
     * 5. int hashCode()：返回存在值的哈希码，如果值不存在 返回 0；
     * 6. void ifPresent(Consumer<? super T> consumer)：如果值存在则使用该值调用 consumer , 否则不做任何事情；
     * 7. boolean isPresent()：如果值存在则方法会返回true，否则返回 false；
     * 8. <U>Optional<U> map(Function<? super T,? extends U> mapper)：如果存在该值，提供的映射方法，如果返回非null，返回一个Optional描述结果；
     * 9. T orElse(T other)：如果存在该值，返回值， 否则返回 other；
     * 10. T orElseGet(Supplier<? extends T> other)：如果存在该值，返回值， 否则触发 other，并返回 other 调用的结果；
     * 11. <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)：如果存在该值，返回包含的值，否则抛出由 Supplier 继承的异常；
     * 12. String toString()：返回一个Optional的非空字符串，用来调试
     * <p>
     * 1.optional的测试
     *
     * @param user
     * @return
     */
    private String getUserName(UserOp user) {
        //1.1创建Optional.empty() 实例
        Optional<Object> empty = Optional.empty();
        boolean equals = empty == null;
        //1.2 Optional.of返回带有指定当前非控值的Optional
        Optional<Object> opOne = Optional.of("23");
        //1.3 Optional.filter如果一个值存在，并且给定的谓词相匹配，返回一个Optional描述的值，否则返回一个空的Optional
        Object o2 = opOne.filter(o -> o.equals("23")).orElseGet(null);
        //1.4 Optional.map() 如果存在值，则应用提供的映射函数，如果结果不为空，则返回一个Optional结果的Optional.否则返回一个空的Optional
        String s = opOne.map(ma -> ma + "_+").get();
        //1.5 Optional.ifPresent()如果存在值，则使用该值调用指定的使用者，否则不执行任何操作 todo
        List<UserOp> opList = new ArrayList<>();
        opOne.ifPresent(ma -> {
            if (ma.equals("23")) {
                System.out.println("ifPresent ---");
            }
        });
        //1.6 Optional.ofNullable():如果非空，返回一个描述指定值的可选的值，否则返回一个空的可选值。
        Optional<Object> o1 = Optional.ofNullable(null);
        //1.7如果Optional中存在值，则返回值，否则抛出NoSuchElementException
        Object o = empty.get();
        Object o3 = opOne.get();
        //1.8 Optional.isPresent()如果存在值，则返回true,否则为false
        boolean present = opOne.isPresent();
        //1.9 Optional.flatMap()如果一个值存在，应用提供的Optional映射函数给它，返回该结果，否则返回一个空的Optional。
        //这种方法类似于map(Function),但是体共的映射器是一个结果已经是Optional映射器，如果被调用，flatMap不会用额外的Optional

        //1.10 Optional.orElse()返回值如果存在，否则返回other
        Optional.ofNullable(user).map(UserOp::getUserName).orElse(null);
        //1.11 Optional.orElseGet()返回值(如果存在)，否则调用other并返回该调用的结果
        String str = "990";
        Object o4 = opOne.orElseGet(() -> UserOp.builder().userName("9090").build());
        //1.12 Optional.orElseThrow()返回包含的值(如果存在),否则抛出由提供的供应商创建的异常
        Object ex = opOne.orElseThrow(() -> new RuntimeException("抛出异常"));

        return Optional.ofNullable(user).map(UserOp::getUserName).orElse(null);
    }


    public static void main(String[] args) {
        new OptionalTest().getUserName(null);
        //new OptionalTest().getUserName(User.builder().userName("姓名").age(12).build());
    }
}

@Builder
@Data
class UserOp {
    private String userName;
    private int age;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}
